#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "A51Cuda.h"
#include <list>

using namespace std;


int count_sample = 0;
int rounds = 8;
struct timeval start_time;
struct timeval stop_time;

void write_log(const char* str) {
	FILE* f_run;
	f_run = fopen("./log", "a");
	fprintf(f_run, "%s\n", str);
	fclose(f_run);
}

void feed_bursts(A51Cuda* a51cuda, const char* plaintext) {
	int samples = 0;
	int* dummy = 0;
	const char* ch = plaintext;
	while (*ch == '0' || *ch == '1') {
		ch++;
		samples++;
	}
	samples -= 63;
	count_sample += samples;
	for (int i = 0; i < samples; i++) {
		uint64_t plain = 0;
		uint64_t plainrev = 0;
		for (int j = 0; j < 64; j++) {
			if (plaintext[i + j] == '1') {
				plain = plain | (1ULL << j);
				plainrev = plainrev | (1ULL << (63 - j));
			}
		}
		for (int k = 0; k < rounds; k++) {
			a51cuda->Submit(plain, k, 140, dummy);
		}
	}
}


uint64_t rnd_uint64(){
	uint64_t out=0;
	for (int i = 0; i < 64; i++) {
		int r = rand() % 2;
		if (r == 1)
			out= out | (1ULL<<i);
	}
	return out;
}

void PrintResult_withPushFront(A51Cuda* a51cuda, const char* log_file){
	uint64_t plain = 0;
	uint64_t start_val;
    uint64_t stop_val;
    uint32_t start_round;
    uint32_t stop_round;
    int* dummy = 0;
	char msg[160];
	FILE* f_log;
	f_log = fopen(log_file, "w");
	printf("%s", log_file);
	printf("\n");

	uint64_t* arr_start;
	uint64_t* arr_stop;
	list< pair<uint64_t,uint64_t> > L;
	int num_push_front=0;
	for (int i = 0; i < count_sample; i++)
		for (int k = 0; k < rounds; k++) {
			while (not a51cuda->PopResult(start_val, stop_val)) {
			}
			L.push_back(pair<uint64_t,uint64_t>(start_val,stop_val));
			if((i + 1)%10==0 and k==5){
				uint64_t input = rnd_uint64();
			    a51cuda->SubmitPartial(input, 5, 140, dummy);
				num_push_front++;
			}
		}

	uint64_t arr_push_front_start[num_push_front];
	uint64_t arr_push_front_stop[num_push_front];
	for (int i = 0; i < num_push_front; i++){
		while (not a51cuda->PopResult(start_val, stop_val)) {
		}
		L.push_back(pair<uint64_t,uint64_t>(start_val,stop_val));
	}


	gettimeofday(&stop_time, NULL);
	unsigned long diff = 1000000 * (stop_time.tv_sec - start_time.tv_sec);
	diff += stop_time.tv_usec - start_time.tv_usec;
	snprintf(msg, 160, "count*rounds=%i front_submit=%d\t running time=%i msec\n",
			count_sample * rounds, num_push_front ,(int) (diff / 1000));
	fprintf(f_log, "%s", msg);

	fprintf(f_log,"number of pop results= count*rounds + front_submit\n");
	fprintf(f_log, "\n==================================POP RESULTS WITH PUSH FRONT==================================\n");

	for (int i = 0; i < count_sample * rounds + num_push_front; i++) {
		snprintf(msg, 160, "Start value=%lx\tStop value=%lx\n", L.front().first,L.front().second);
		fprintf(f_log,"%s", msg);
		L.pop_front();
	}
	fclose(f_log);
}


int main(int argc, char* argv[]) {
//	A5AtiInit(8, 12, 0xffffffff, 1);
    A51Cuda* a51cuda = new A51Cuda(8, 140);
	//test 01 burst
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda, "100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	PrintResult_withPushFront(a51cuda,"01burst_pushfront.log");

	//test 02 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda, "100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda, "101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	PrintResult_withPushFront(a51cuda,"02bursts_pushfront.log");

	//test 03 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda,"100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda,"101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	feed_bursts(a51cuda,"000101010111010101000000100000000001010101010001000010000001000101111101010100000010000000010111010101000000001000");
	PrintResult_withPushFront(a51cuda,"03bursts_pushfront.log");

	//test 04 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda,"100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda,"101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	feed_bursts(a51cuda,"000101010111010101000000100000000001010101010001000010000001000101111101010100000010000000010111010101000000001000");
	feed_bursts(a51cuda,"010100001010101110111111010100010000001010101011111111010101000010001010111111110101010100001010101010111101010101");
	PrintResult_withPushFront(a51cuda,"04bursts_pushfront.log");

	//test 05 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda,"100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda,"101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	feed_bursts(a51cuda,"000101010111010101000000100000000001010101010001000010000001000101111101010100000010000000010111010101000000001000");
	feed_bursts(a51cuda,"010100001010101110111111010100010000001010101011111111010101000010001010111111110101010100001010101010111101010101");
	feed_bursts(a51cuda,"101000110001100000111010011111100000010010000001000101000110001100000101111111111000101010111000000111110101000101");
	PrintResult_withPushFront(a51cuda,"05bursts_pushfront.log");

	//test 10 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda,"100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda,"101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	feed_bursts(a51cuda,"000101010111010101000000100000000001010101010001000010000001000101111101010100000010000000010111010101000000001000");
	feed_bursts(a51cuda,"010100001010101110111111010100010000001010101011111111010101000010001010111111110101010100001010101010111101010101");
	feed_bursts(a51cuda,"101000110001100000111010011111100000010010000001000101000110001100000101111111111000101010111000000111110101000101");
	feed_bursts(a51cuda,"010010001001111101111101101000100001111001100110000000111010111011100011110111000000110010010110001011011110011001");
	feed_bursts(a51cuda,"000010011110100101110000101110000000011101011001010011010011001000101001010001011001001010000001101011011100111110");
	feed_bursts(a51cuda,"110001000001100010101100000101010100011000101110100110011100010000101000110010001110111001010000001000001110001011");
	feed_bursts(a51cuda,"100000001010010011111000101001110001001001011011001010011001100110010101011001000000000100011011111100011101010000");
	feed_bursts(a51cuda,"101010001011111000010000010001111011111101001110000111000011110010011100011111010110010010001100011100010101001111");
	PrintResult_withPushFront(a51cuda,"10bursts_pushfront.log");

	//test 20 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda,"100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda,"101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	feed_bursts(a51cuda,"000101010111010101000000100000000001010101010001000010000001000101111101010100000010000000010111010101000000001000");
	feed_bursts(a51cuda,"010100001010101110111111010100010000001010101011111111010101000010001010111111110101010100001010101010111101010101");
	feed_bursts(a51cuda,"101000110001100000111010011111100000010010000001000101000110001100000101111111111000101010111000000111110101000101");
	feed_bursts(a51cuda,"010010001001111101111101101000100001111001100110000000111010111011100011110111000000110010010110001011011110011001");
	feed_bursts(a51cuda,"000010011110100101110000101110000000011101011001010011010011001000101001010001011001001010000001101011011100111110");
	feed_bursts(a51cuda,"110001000001100010101100000101010100011000101110100110011100010000101000110010001110111001010000001000001110001011");
	feed_bursts(a51cuda,"100000001010010011111000101001110001001001011011001010011001100110010101011001000000000100011011111100011101010000");
	feed_bursts(a51cuda,"101010001011111000010000010001111011111101001110000111000011110010011100011111010110010010001100011100010101001111");
	feed_bursts(a51cuda,"010100011000110001010000011001011100101011010100111010010111101110001011111100111011110111001010111101011011111011");
	feed_bursts(a51cuda,"110100010000110111100011110001011011100010001000110010010111110100011001010010111010000110111011000100100100101001");
	feed_bursts(a51cuda,"001110100011010110001110110001101011101100101000100010001001100111101110000000000011001000010101001000100001101000");
	feed_bursts(a51cuda,"100111101000111110101110000001011100000110000000111011100001100000100110000001010001001001011010100111101010100011");
	feed_bursts(a51cuda,"100100010110000110101010000100101101110101001110101001111100000011111011110001100001001100101000000001110010001001");
	feed_bursts(a51cuda,"011010001001101001110101011000101001111111110110111110010101010000010111001011100010110100101011011010101001101011");
	feed_bursts(a51cuda,"110001001100011001010010111011110111001010011110111110101100101110110110010000100010111101001111011101101111111001");
	feed_bursts(a51cuda,"001101110110000010101110000100000001000011001110000001110010101101000110100100001100010010110101101011110110000101");
	feed_bursts(a51cuda,"011100011100010001010100100110111110001010001010000011100100101001100100011000011100100001111010011100000100000101");
	feed_bursts(a51cuda,"010011101111110100100101110001100010011100001111010100010110001100110001000100010011001001010110101011010111010101");
	PrintResult_withPushFront(a51cuda,"20bursts_pushfront.log");

	//test 30 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda,"100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda,"101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	feed_bursts(a51cuda,"000101010111010101000000100000000001010101010001000010000001000101111101010100000010000000010111010101000000001000");
	feed_bursts(a51cuda,"010100001010101110111111010100010000001010101011111111010101000010001010111111110101010100001010101010111101010101");
	feed_bursts(a51cuda,"101000110001100000111010011111100000010010000001000101000110001100000101111111111000101010111000000111110101000101");
	feed_bursts(a51cuda,"010010001001111101111101101000100001111001100110000000111010111011100011110111000000110010010110001011011110011001");
	feed_bursts(a51cuda,"000010011110100101110000101110000000011101011001010011010011001000101001010001011001001010000001101011011100111110");
	feed_bursts(a51cuda,"110001000001100010101100000101010100011000101110100110011100010000101000110010001110111001010000001000001110001011");
	feed_bursts(a51cuda,"100000001010010011111000101001110001001001011011001010011001100110010101011001000000000100011011111100011101010000");
	feed_bursts(a51cuda,"101010001011111000010000010001111011111101001110000111000011110010011100011111010110010010001100011100010101001111");

	feed_bursts(a51cuda,"010100011000110001010000011001011100101011010100111010010111101110001011111100111011110111001010111101011011111011");
	feed_bursts(a51cuda,"110100010000110111100011110001011011100010001000110010010111110100011001010010111010000110111011000100100100101001");
	feed_bursts(a51cuda,"001110100011010110001110110001101011101100101000100010001001100111101110000000000011001000010101001000100001101000");
	feed_bursts(a51cuda,"100111101000111110101110000001011100000110000000111011100001100000100110000001010001001001011010100111101010100011");
	feed_bursts(a51cuda,"100100010110000110101010000100101101110101001110101001111100000011111011110001100001001100101000000001110010001001");
	feed_bursts(a51cuda,"011010001001101001110101011000101001111111110110111110010101010000010111001011100010110100101011011010101001101011");
	feed_bursts(a51cuda,"110001001100011001010010111011110111001010011110111110101100101110110110010000100010111101001111011101101111111001");
	feed_bursts(a51cuda,"001101110110000010101110000100000001000011001110000001110010101101000110100100001100010010110101101011110110000101");
	feed_bursts(a51cuda,"011100011100010001010100100110111110001010001010000011100100101001100100011000011100100001111010011100000100000101");
	feed_bursts(a51cuda,"010011101111110100100101110001100010011100001111010100010110001100110001000100010011001001010110101011010111010101");

	feed_bursts(a51cuda,"000011110010101110010111010001011000001000011001011010100010010110010111011000101110001011110111110001010110011000");
	feed_bursts(a51cuda,"010100100100101111100101100010011111011001100010001000011010101100110010000001001001011100110110011111111001110011");
	feed_bursts(a51cuda,"000101101111010011111001000010000000100011101110010100110000110010110011001100101110101110110000000101101011110111");
	feed_bursts(a51cuda,"001010110000011000111111101011000100010011001010110001010100011010101011011111110001010000111001100001001101111010");
	feed_bursts(a51cuda,"100100100010110110011010101001111011001110110000000011110101110101111001110001001101011001010000101101110101011010");
	feed_bursts(a51cuda,"001000111010100010100001100011010110010000011011111110111001100111110101010010111001010110111100110101110000000001");
	feed_bursts(a51cuda,"000100111101110011011010010111101000010011001111000000110000010011110001000000110010100001010100110001100100010001");
	feed_bursts(a51cuda,"110101101100110001101110000001001110001011111111100000001101000000100010001011101101111001000001001110010111001000");
	feed_bursts(a51cuda,"010100000011111101011100111000000011011101000101010111100011011011100010000110110111100100001010001111010010101101");
	feed_bursts(a51cuda,"101101100011000001111100011101101001011010001000101010110100110101101000111010000100111010100101011001001100011100");
	PrintResult_withPushFront(a51cuda,"30bursts_pushfront.log");

	//test 50 bursts
	count_sample = 0;
	gettimeofday(&start_time, NULL);
	feed_bursts(a51cuda,"100000000101110101010100000000000001000111110101010100001000000100010111010100010000000000010001011101010100000000");
	feed_bursts(a51cuda,"101010111111110101000100101010101110111101010100000000101010101111111101010001000010101010101111011101010000001000");
	feed_bursts(a51cuda,"000101010111010101000000100000000001010101010001000010000001000101111101010100000010000000010111010101000000001000");
	feed_bursts(a51cuda,"010100001010101110111111010100010000001010101011111111010101000010001010111111110101010100001010101010111101010101");
	feed_bursts(a51cuda,"101000110001100000111010011111100000010010000001000101000110001100000101111111111000101010111000000111110101000101");
	feed_bursts(a51cuda,"010010001001111101111101101000100001111001100110000000111010111011100011110111000000110010010110001011011110011001");
	feed_bursts(a51cuda,"000010011110100101110000101110000000011101011001010011010011001000101001010001011001001010000001101011011100111110");
	feed_bursts(a51cuda,"110001000001100010101100000101010100011000101110100110011100010000101000110010001110111001010000001000001110001011");
	feed_bursts(a51cuda,"100000001010010011111000101001110001001001011011001010011001100110010101011001000000000100011011111100011101010000");
	feed_bursts(a51cuda,"101010001011111000010000010001111011111101001110000111000011110010011100011111010110010010001100011100010101001111");

	feed_bursts(a51cuda,"010100011000110001010000011001011100101011010100111010010111101110001011111100111011110111001010111101011011111011");
	feed_bursts(a51cuda,"110100010000110111100011110001011011100010001000110010010111110100011001010010111010000110111011000100100100101001");
	feed_bursts(a51cuda,"001110100011010110001110110001101011101100101000100010001001100111101110000000000011001000010101001000100001101000");
	feed_bursts(a51cuda,"100111101000111110101110000001011100000110000000111011100001100000100110000001010001001001011010100111101010100011");
	feed_bursts(a51cuda,"100100010110000110101010000100101101110101001110101001111100000011111011110001100001001100101000000001110010001001");
	feed_bursts(a51cuda,"011010001001101001110101011000101001111111110110111110010101010000010111001011100010110100101011011010101001101011");
	feed_bursts(a51cuda,"110001001100011001010010111011110111001010011110111110101100101110110110010000100010111101001111011101101111111001");
	feed_bursts(a51cuda,"001101110110000010101110000100000001000011001110000001110010101101000110100100001100010010110101101011110110000101");
	feed_bursts(a51cuda,"011100011100010001010100100110111110001010001010000011100100101001100100011000011100100001111010011100000100000101");
	feed_bursts(a51cuda,"010011101111110100100101110001100010011100001111010100010110001100110001000100010011001001010110101011010111010101");

	feed_bursts(a51cuda,"000011110010101110010111010001011000001000011001011010100010010110010111011000101110001011110111110001010110011000");
	feed_bursts(a51cuda,"010100100100101111100101100010011111011001100010001000011010101100110010000001001001011100110110011111111001110011");
	feed_bursts(a51cuda,"000101101111010011111001000010000000100011101110010100110000110010110011001100101110101110110000000101101011110111");
	feed_bursts(a51cuda,"001010110000011000111111101011000100010011001010110001010100011010101011011111110001010000111001100001001101111010");
	feed_bursts(a51cuda,"100100100010110110011010101001111011001110110000000011110101110101111001110001001101011001010000101101110101011010");
	feed_bursts(a51cuda,"001000111010100010100001100011010110010000011011111110111001100111110101010010111001010110111100110101110000000001");
	feed_bursts(a51cuda,"000100111101110011011010010111101000010011001111000000110000010011110001000000110010100001010100110001100100010001");
	feed_bursts(a51cuda,"110101101100110001101110000001001110001011111111100000001101000000100010001011101101111001000001001110010111001000");
	feed_bursts(a51cuda,"010100000011111101011100111000000011011101000101010111100011011011100010000110110111100100001010001111010010101101");
	feed_bursts(a51cuda,"101101100011000001111100011101101001011010001000101010110100110101101000111010000100111010100101011001001100011100");

	feed_bursts(a51cuda,"110001011011010010001011000100101110101010111100111001111101010011111000001001011111110100110010110011000101000101");
	feed_bursts(a51cuda,"010111010001100100001010110000110010100001100010110111011001010000000011111001001000001111101011100111011100000100");
	feed_bursts(a51cuda,"001111101001000001110110111000011100101100001111000010110010110111000001001001010110010110100111010110111111010011");
	feed_bursts(a51cuda,"001010110100110011011101011000110011101001111111011110010100001000101011101100111011011101011011101010010110001101");
	feed_bursts(a51cuda,"110101001010011110111100101011011101110000110111010001111101011101010010000110001001010111110111011101010111010101");
	feed_bursts(a51cuda,"010010100011000001000101100111111110011000100100101001111111011100011101110110000010101101100100011100011110011010");
	feed_bursts(a51cuda,"000101100111101110010011001111111011010011010101101100001001000111111001000001101111110100011110010111101011110011");
	feed_bursts(a51cuda,"001111111111110101111001001101111001100101110110101111001111111000000001011111111110111000111010000101101101001010");
	feed_bursts(a51cuda,"101111010000000010000100001011110010000001000111010010001010101000010100101110111010100011010100111101110001010101");
	feed_bursts(a51cuda,"000001001011011001011010001101110001111000010111111000001010101111010000110010101001000001101111000001010101110011");

	feed_bursts(a51cuda,"110101000001011111010100010110100010101111010000110100000000100010100011110111111110000111001011011001010110001110");
	feed_bursts(a51cuda,"101001001010000010111100010100100010110100100000100111000000110000000000011110001010100111111011101111001111100001");
	feed_bursts(a51cuda,"000110110001001101101000101011100101110011101111001011001011101001001000000110111100001110101000100011000010001101");
	feed_bursts(a51cuda,"010111101011100000100000111101011011110111110100110001100000101110110111011110111000111000010011110000101001110011");
	feed_bursts(a51cuda,"000100001010111111011101001110010000001001111110110100110110111111000101111011100111000001011000111101001110111100");
	feed_bursts(a51cuda,"100111100011100110010011101110010111000001001010100010101111100011010011111100100101100010000111010010100000101100");
	feed_bursts(a51cuda,"100001110000111101111111011110001001110111000101101010010011110110110010000100010111011111011111111010111100110110");
	feed_bursts(a51cuda,"100000010001000110001011011101101101110100010110010011011010101010101010011010011011100111011110110010000100001111");
	feed_bursts(a51cuda,"100001001110101010111111100111110111100100101000111111001001011000111101011010111110011111111010110000001001101010");
	feed_bursts(a51cuda,"111111111010000111111101101000101000100110000000000011100001110001001000001101011011101111001011010001101000001010");
	PrintResult_withPushFront(a51cuda,"50bursts_pushfront.log");


//	A5AtiShutdown();
    delete a51cuda;
}

